package com.tech.distribute_lock;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author litianlin
 * @date 2023/12/6 12:08
 * @description:
 */
@EnableAspectJAutoProxy
@Aspect
@Component
public class DistributeLockAnnoAspect {
    @Resource(name="")
    private DistributeLockStategy distributeLockStategy;

    @Pointcut("@annotation(anno)")
    public void pointcut(DistributeLockAnno anno){}

    @Around("pointcut(anno)")
    public Object around(ProceedingJoinPoint joinPoint, DistributeLockAnno anno) throws Throwable {
        System.out.println("基于注解拦截的切面类");
        String lockKey = "";
        boolean hasLock = false;
        try {
            lockKey = getLockKey(joinPoint, anno);
            int millis = anno.expireSecond() * 1000;
            hasLock = distributeLockStategy.tryLock(lockKey, millis);
            int maxTry = anno.maxTry();
            while(!hasLock){
                if(maxTry--==0){
                    throw new RuntimeException("超过尝试次数，未获得全局锁");
                }
                distributeLockStategy.lockWait(millis);
                hasLock = distributeLockStategy.tryLock(lockKey, millis);
            }
            Object proceed = joinPoint.proceed();
            return proceed;
        }catch (Throwable t){

            throw t;
        }finally {
            if(hasLock){
                distributeLockStategy.unLock(lockKey);
            }
        }
    }

    private String getLockKey(ProceedingJoinPoint joinPoint, DistributeLockAnno anno) {
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String spel = anno.spel();
        String space = anno.space();
        return space+SpELParserUtils.parse(signature.getMethod(), args, spel, String.class);
    }

    public static void main(String[] args) {
        ExpressionParser ep= new SpelExpressionParser();
        //创建上下文变量
        EvaluationContext ctx = new StandardEvaluationContext();
        //在上下文中设置变量，变量名为name，内容为Hello
        ctx.setVariable("name", "Hello");
        System.out.println(ep.parseExpression("#name").getValue(ctx));//输出：Hello

    }
}
